package com.esteel.settlement.pa.packet;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * 平安对接接口的基类 用于对数据格式的转换
 * 
 * @author zhangxiuzhi
 *
 */

@XmlAccessorType(XmlAccessType.FIELD)
public abstract class PaPacket implements Serializable {

	public static String RMB = "RMB";

	public static String SUCCESS = "000000";

	public static SimpleDateFormat SFDate = new SimpleDateFormat("yyyyMMdd");

	DecimalFormat df = new DecimalFormat("######0.00");

	Charset charset = Charset.forName("GBK");

	// 报文请求类型 请求
	public static String REQUEST = "01";

	// 报文请求类型 请求
	public static String RESPONSE = "02";

	
	// 保留域
	@XmlElement(name = "Reserve")
	private String reserve;

	@XmlTransient
	protected PacketHeader packetHeader = new PacketHeader();

	@XmlTransient
	protected BusinessHeader buisinessHeader = new BusinessHeader();

	// 交易网代码
	@XmlTransient
	@NotEmpty
	private String qydm;

	// 交易网流水号
	@XmlElement(name = "ThirdLogNo")
	@Length(max = 20)
	@NotEmpty
	private String thirdLogNo;

	// 服务类型
	@XmlTransient
	@NotEmpty
	@Pattern(regexp = "01|02")
	private String servType;

	// 交易时间
	@XmlTransient
	@NotNull
	@DateTimeFormat(pattern = "yyyyMMdd")
	private Date transDate;

	// 操作员号
	@XmlTransient
	private String counterId;

	// 交易码
	@XmlTransient
	@NotNull
	@Length(min = 1, max = 4)
	private String tranFunc;
	
	public  PaPacket(){
		this.setTranFunc(tranFunc());
	}
	
	protected abstract String tranFunc();

	public String getReserve() {
		return reserve;
	}

	public void setReserve(String reserve) {
		this.reserve = reserve;
	}

	public String getQydm() {
		return qydm;
	}
	


	public void setQydm(String qydm) {
		this.qydm = qydm;
		// 交易网代码
		this.packetHeader.setQydm(this.getQydm());
		this.buisinessHeader.setQydm(this.qydm);
	}

	public String getThirdLogNo() {
		return thirdLogNo;
	}

	public void setThirdLogNo(String thirdLogNo) {
		this.thirdLogNo = thirdLogNo;
		// 请求系统流水号
		this.packetHeader.setThirdLogNo(this.getThirdLogNo());
		this.buisinessHeader.setThirdLogNo(this.getThirdLogNo());
	}

	public String getServType() {
		return servType;
	}

	public void setServType(String servType) {
		this.servType = servType;
		// 服务类型 01 请求 02 应答
		this.packetHeader.setServType(this.getServType());
		this.buisinessHeader.setServType(this.getServType());
	}

	public Date getTransDate() {
		return transDate;
	}

	public void setTransDate(Date transDate) {
		this.transDate = transDate;
		// 交易时间
		this.packetHeader.setTranDate(this.getTransDate());
		this.buisinessHeader.setTranDate(this.getTransDate());
	}

	public String getCounterId() {
		return counterId;
	}

	public void setCounterId(String counterId) {
		this.counterId = counterId;
		// 操作员号
		this.packetHeader.setCounterId(counterId);
		this.buisinessHeader.setCounterId(counterId);
	}

	public String getTranFunc() {
		return tranFunc;
	}

	public void setTranFunc(String tranFunc) {
		this.tranFunc = tranFunc;
		this.buisinessHeader.setTranFunc(tranFunc);
	}

	public void setRspCode(String rspCode) {
		this.buisinessHeader.setRspCode(rspCode);
		this.packetHeader.setRspCode(rspCode);
	}

	public String getRspCode() {
		return this.buisinessHeader.getRspCode();
	}

	public void setRspMsg(String rspMsg) {
		this.buisinessHeader.setRspMsg(rspMsg);
		this.packetHeader.setRspMsg(rspMsg);
	}

	public String getRspMsg() {
		return this.buisinessHeader.getRspMsg();
	}

	/**
	 * 解析报文头
	 * 
	 * @param packetHeader
	 */
	private void analyzePacketHeader(byte[] packetHeader) {
		this.packetHeader.analyze(packetHeader);
	}

	/**
	 * 解析业务报文头
	 * 
	 * @param businesserHeader
	 */
	private void analyzeBusinsserHeader(byte[] businesserHeader) {
		this.buisinessHeader.analyze(businesserHeader);
	}

	/**
	 * 将报文编组成可以发送的字符串报文
	 * 
	 * @return
	 */

	public String marshal() {

		Assert.notNull(this.packetHeader);
		Assert.notNull(this.buisinessHeader);

		// 业务报问题
		String data = this.getString();

		// 设置报文中的公共的值
		// 交易网代码

		this.packetHeader.setQydm(this.getQydm());
		this.buisinessHeader.setQydm(this.qydm);

		// 请求系统流水号
		this.packetHeader.setThirdLogNo(this.getThirdLogNo());
		this.buisinessHeader.setThirdLogNo(this.getThirdLogNo());

		// 服务类型 01 请求 02 应答
		this.packetHeader.setServType(this.getServType());
		this.buisinessHeader.setServType(this.getServType());

		// 交易时间
		this.packetHeader.setTranDate(this.getTransDate());
		this.buisinessHeader.setTranDate(this.getTransDate());

		// 设置报文长度
		this.packetHeader.setPacketLength(BusinessHeader.HEADERLEN + data.getBytes(charset).length);
		this.buisinessHeader.setLength(data.getBytes(charset).length);

		// 操作员号
		this.packetHeader.setCounterId(this.getCounterId());
		this.buisinessHeader.setCounterId(this.getCounterId());

		// 设置操作代码
		// this.buisinessHeader.setTranFunc(this.getTranFunc());

		byte[] cs = this.packetHeader.getPacketHeader();
		StringBuilder sb = new StringBuilder();
		sb.append(new String(cs, charset));
		sb.append(new String(this.buisinessHeader.getBusinessHeader(), charset));
		sb.append(data);
		return sb.toString();
	}

	/**
	 * 生成需要的报文字符串
	 * 
	 * @return
	 */
	public String getString() {
		StringBuilder sb = new StringBuilder();
		try {
			for (String fName : this.order()) {
				Object obj = getValue(fName);
				if (obj == null) {
					sb.append("");
				}
				if (obj instanceof String) {
					sb.append((String) obj);
				}
				if (obj instanceof Integer) {
					sb.append(((Integer) obj).intValue());
				}
				if (obj instanceof Long) {
					sb.append(((Long) obj).intValue());
				}
				if (obj instanceof Double) {
					sb.append(df.format((Double) obj));
				}
				if (obj instanceof Date) {
					sb.append(SFDate.format(obj));
				}
				sb.append("&");
			}

		} catch (NoSuchFieldException | SecurityException | NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {

			e.printStackTrace();
		}
		// sb.deleteCharAt(sb.length() - 1);
		return sb.toString();
	}

	/**
	 * 取得属性名字时 用于获得属性值
	 * 
	 * @param fName
	 * @return
	 * @throws NoSuchFieldException
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	private Object getValue(String fName) throws NoSuchFieldException, SecurityException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

		fName = fName.substring(0, 1).toUpperCase() + fName.substring(1);
		Method method = this.getClass().getMethod("get" + fName);
		Assert.notNull(method);

		return method.invoke(this);

	}

	/**
	 * 设置对象的值
	 * 
	 * @param fName
	 * @param value
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws ParseException
	 */
	private void setValue(Object obj,String fieldName, List<String> values)
			throws NoSuchMethodException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, ParseException {

		if (values == null||values.isEmpty()) {
			return;
		}
		
		//用于判断是否去掉values中的第一个元素，默认情况删除，但在处理递归调用的时候 不删除
		boolean isMove=true;
		
		String value = values.get(0);
		String fName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
		Method get = obj.getClass().getMethod("get" + fName);

		Method method = obj.getClass().getMethod("set" + fName, get.getReturnType());
		Assert.notNull(method);

		switch (get.getReturnType().getSimpleName()) {
		case "String": {
			method.invoke(obj, value);
			break;
		}
		case "int":
		case "Integer": {
			if (value.indexOf(".") > -1) {
				value = value.substring(0, value.indexOf("."));
			}
			method.invoke(obj, new Integer(value));
			break;
		}
		case "double":
		case "Double": {
			method.invoke(obj, df.parse(value));
			break;
		}
		case "long":
		case "Long": {
			if (value.indexOf(".") > -1) {
				value = value.substring(0, value.indexOf("."));
			}
			method.invoke(obj, new Long(value));
			break;
		}
		case "Date": {
			try{
				Date date = SFDate.parse(value);
				method.invoke(obj, date);
			}catch(Exception ex){
			}
			break;
		}
		case "List":{
			
			Field field = obj.getClass().getDeclaredField(fieldName);
			ArraySizeMethod arraySizeMethod = field.getAnnotation(ArraySizeMethod.class);
			//循环记录的条数 默认1
			int numSize = 1;
			if (arraySizeMethod!=null){
				String sizeMethodName = arraySizeMethod.value();
				if (!StringUtils.isEmpty(sizeMethodName)){
					Method sizeMethod = obj.getClass().getMethod(sizeMethodName);
					numSize = ((int) sizeMethod.invoke(obj));
				
				}
			}
			List<ResultArray> list = new ArrayList<ResultArray>();
			Type fc = field.getGenericType();
			if (fc instanceof ParameterizedType){
				ParameterizedType pt = (ParameterizedType) fc;  
                Class<?> genericClazz = (Class<?>)pt.getActualTypeArguments()[0];
                try {
                	ResultArray result = (ResultArray) genericClazz.newInstance();
                	String[] orders = result.order();
                	
                	for (int i=0;i<numSize;i++){
	                	for (String str : orders){
	                		setValue(result,str,values);
	                	}
	                	list.add(result);
	                	result = (ResultArray) genericClazz.newInstance();
                	}
				} catch (InstantiationException e) {
	
					e.printStackTrace();
				}
			}
			method.invoke(obj, list);
			isMove = false;
			break;
		}
		default:{
			System.out.println(get.getReturnType().getSimpleName());
		}
		}
		//去掉队列中的第一个元素
		if (isMove){
			values.remove(0);
		}
	}

	/**
	 * 根据各处的
	 * 
	 * @param str
	 */
	public void analyze(String packetStr) {


		byte[] src = packetStr.getBytes(charset);
		Assert.isTrue(src.length > 344);
		byte[] ph = new byte[222];
		byte[] bh = new byte[122];

		System.arraycopy(src, 0, ph, 0, ph.length);
		System.arraycopy(src, 222, bh, 0, bh.length);

		this.analyzePacketHeader(ph);
		this.analyzeBusinsserHeader(bh);

		byte[] data = new byte[src.length - 344];
		System.arraycopy(src, 344, data, 0, data.length);

		String str = new String(data, charset);

		// 将头文件中的属性值设置到公共报文中
		this.setCounterId(this.buisinessHeader.getCounterId());
		this.setQydm(this.buisinessHeader.getQydm());
		this.setTransDate(this.buisinessHeader.getTranDate());
		this.setServType(this.buisinessHeader.getServType());
		this.setThirdLogNo(this.buisinessHeader.getThirdLogNo());
		this.setTranFunc(this.buisinessHeader.getTranFunc());

		String[] strs = str.split("&");
		List<String> list = new LinkedList<String>();
		list.addAll(Arrays.asList(strs));
		String[] fNames = this.order();
		String[] values = new String[fNames.length];
		System.arraycopy(strs, 0, values, 0, values.length > strs.length ? strs.length : values.length);
		// Assert.isTrue(fNames.length >= strs.length);

//		int index = 0;
		try {
			for (String fname : fNames) {
//				setValue(fname, values[index]);
				setValue(this,fname, list);
//				index++;
			}
		} catch (NoSuchMethodException | SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException | InvocationTargetException | ParseException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 返回报文的生成顺序
	 * 
	 * @return
	 */
	protected abstract String[] order();
}
